#include <pthread.h>
#include <binder/ProcessState.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <dtvservice/IDtvService.h>
#include <semaphore.h>

using namespace android;

class BufferListener : public BnDtvBufferListener
{
public:
	BufferListener(sem_t *sem):mSemaphore(sem){}
	virtual void DataArraived()
	{
		sem_post(mSemaphore);
	}
private:
	sem_t *mSemaphore;
};

int main(int argc,char *argv[])
{
	ProcessState::self()->startThreadPool();

	sp<IServiceManager> sm = defaultServiceManager();

	sp<IBinder> b = sm->getService(String16("DtvService"));
	
	sp<IDtvService> dtv = interface_cast<IDtvService>(b);

	int r;

	tuner_capability_t tcap;

	r = dtv->GetTunerCapability(&tcap);
	if(r<0)
	{
		printf("GetTunerCapability failed!\n");
	}

	printf("tcap.count=%d\n",tcap.count);
	printf("tcap.types[0]=%d\n",tcap.types[0]);
	
	demux_capability_t dcap;

	r = dtv->GetDemuxCapability(&dcap);
	if(r<0)
	{
		printf("GetDemuxCapability failed!\n");
	}

	printf("dcap.demux_count=%d\n",dcap.demux_count);
	printf("dcap.channel_count=%d\n",dcap.channel_count);
	printf("dcap.filter_count=%d\n",dcap.filter_count);
	printf("dcap.descrambler_count=%d\n",dcap.descrambler_count);

	sp<IDtvTuner> tuner;
	r = dtv->GetTuner(0,&tuner);
	if(r<0)
	{
		printf("GetTuner failed!\n");
	}

	int index;
	r = tuner->GetIndex(&index);
	if(r<0)
	{
		printf("GetIndex failed!\n");
	}
	printf("Tuner Index = %d\n",index);

	tuner_param_t param;
	param.type=TUNER_TYPE_DVBC;
	param.dvbc.frequency=666000;
	param.dvbc.symbol_rate=6875000;
	param.dvbc.qam=TUNER_QAM_MODE_64QAM;
	param.dvbc.spectrum=TUNER_SPECTRUM_MODE_AUTO;
	tuner->SetParameter(&param);
	if(r<0)
	{
		printf("GetTuner failed!\n");
	}

	bool locked;
	for(int i=0;i<20;i++)
	{
		r=tuner->GetLocked(&locked);
		if(r<0)
		{
			printf("tuner->GetStatus error\n");
			return -1;
		}
		if(locked)
		{
			printf("(%d)try %d times\n",locked,i+1);
			break;
		}
	}

	tuner_status_t status;
	r=tuner->GetStatus(&status);
	if(r<0)
	{
		printf("tuner->GetStatus error\n");
		return -1;
	}
	printf("status.locked=%d\n",status.locked);
	printf("status.strength=%d\n",status.strength);
	printf("status.qulity=%d\n",status.qulity);
	printf("status.power=%d\n",status.power);
	printf("status.snr=%d\n",status.snr);
	printf("status.ber=%d\n",status.ber);
	printf("status.param.dvbc.frequency=%d\n",status.param.dvbc.frequency);
	printf("status.param.dvbc.symbol_rate=%d\n",status.param.dvbc.symbol_rate);
	printf("status.param.dvbc.qam=%d\n",status.param.dvbc.qam);
	printf("status.param.dvbc.spectrum=%d\n",status.param.dvbc.spectrum);

	
	sp<IDtvDemux> demux;
	r = dtv->GetDemux(2,&demux);
	if(r<0)
	{
		printf("GetDemux failed!\n");
	}

	r=demux->LinkTuner(tuner);
	if(r<0)
	{
		printf("LinkTuner failed!\n");
	}

	sp<IDtvChannel> channel;
	r=demux->CreateChannel(DEMUX_CHANNEL_TYPE_SECTION,
		DEMUX_CHANNEL_CRC_ENABLE,1024*4,&channel);
	if(r<0)
	{
		printf("CreateChannel failed!\n");
	}

	r=channel->SetPid(0x11);
	if(r<0)
	{
		printf("SetPid failed!\n");
	}

	sp<IDtvFilter> filter;
	demux_filter_param_t fparam;
	memset(&fparam,0,sizeof(demux_filter_param_t));
	fparam.depth=1;
	fparam.match[0]=0x42;
	fparam.mask[0]=0xF0;
	r=demux->CreateFilter(&fparam,&filter);
	if(r<0)
	{
		printf("CreateFilter failed!\n");
	}

	r=filter->AssociateChannel(channel);
	if(r<0)
	{
		printf("AssociateChannel failed!\n");
	}

	
	sp<IDtvChannel> channel2;
	r=demux->CreateChannel(DEMUX_CHANNEL_TYPE_SECTION,
		DEMUX_CHANNEL_CRC_ENABLE,1024*4,&channel2);
	if(r<0)
	{
		printf("CreateChannel failed!\n");
	}

	r=channel2->SetPid(0x12);
	if(r<0)
	{
		printf("SetPid failed!\n");
	}

	sp<IDtvFilter> filter2;
	memset(&fparam,0,sizeof(demux_filter_param_t));
	fparam.depth=1;
	fparam.match[0]=0x4E;
	fparam.mask[0]=0xFE;
	r=demux->CreateFilter(&fparam,&filter2);
	if(r<0)
	{
		printf("CreateFilter failed!\n");
	}

	r=filter2->AssociateChannel(channel2);
	if(r<0)
	{
		printf("AssociateChannel failed!\n");
	}

	sp<IDtvFilter> filter3;
	memset(&fparam,0,sizeof(demux_filter_param_t));
	fparam.depth=1;
	fparam.match[0]=0x50;
	fparam.mask[0]=0xF0;
	r=demux->CreateFilter(&fparam,&filter3);
	if(r<0)
	{
		printf("CreateFilter failed!\n");
	}

	r=filter3->AssociateChannel(channel2);
	if(r<0)
	{
		printf("AssociateChannel failed!\n");
	}

	sp<IDtvFilter> filter4;
	memset(&fparam,0,sizeof(demux_filter_param_t));
	fparam.depth=1;
	fparam.match[0]=0x60;
	fparam.mask[0]=0xF0;
	r=demux->CreateFilter(&fparam,&filter4);
	if(r<0)
	{
		printf("CreateFilter failed!\n");
	}

	r=filter4->AssociateChannel(channel2);
	if(r<0)
	{
		printf("AssociateChannel failed!\n");
	}

	sp<IDtvBuffer> buffer;
	r=demux->CreateBuffer(1024*64,&buffer);
	if(r<0)
	{
		printf("CreateBuffer failed!\n");
	}

	r=channel->LinkBuffer(buffer);
	if(r<0)
	{
		printf("LinkBuffer failed!\n");
	}
	r=channel2->LinkBuffer(buffer);
	if(r<0)
	{
		printf("LinkBuffer failed!\n");
	}
	int handle;
	buffer->GetHandle(&handle);
	printf("buffer_handle=%d\n",handle);

	sem_t sem;
	sem_init(&sem,0,0);

	sp<IDtvBufferListener> listener=new BufferListener(&sem);
	r=buffer->SetListener(listener);
	if(r<0)
	{
		printf("SetListener failed!\n");
	}
	listener=NULL;

	r=channel->Start();
	if(r<0)
	{
		printf("Start failed!\n");
	}
	r=channel2->Start();
	if(r<0)
	{
		printf("Start failed!\n");
	}


	sp<IMemoryHeap> memory;
	r=buffer->GetMemory(&memory);
	if(r<0)
	{
		printf("GetMemory failed!\n");
	}

	uint8_t *bufferBase=(uint8_t*)memory->getBase();
	int bufferSize=memory->getSize();

	printf("base=%p\nsize=%d\n",bufferBase,bufferSize);

	for(int i=0;i<100000;i++)
	{
		sem_wait(&sem);
		sem_wait(&sem);
		
		int readOffset;
		int dataSize;
		bool read=true;
		while(read)
		{
			sp<IDtvChannel> chn;
			read=false;
		
			r=buffer->BeginReadData(&readOffset,&dataSize,&chn);
			if(r<0)
			{
				//printf("BeginReadData failed!\n");
				read=false;
				continue;
			}
			
			if(i%10==0)
			{
				int bufferDataSize;
				r=buffer->GetDataSize(&bufferDataSize);
				if(r<0)
				{
					printf("GetDataSize failed!\n");
				}

				int pid;
				r=chn->GetPid(&pid);
				if(r<0)
				{
					printf("GetPid failed!\n");
				}
				
				printf("pid=%d,readOffset=%d,dataSize=%d,bufferDataSize=%d\n",
					pid,readOffset,dataSize,bufferDataSize);
				if(readOffset<bufferSize-10)
				{
					for(int j=0;j<8;j++)
					{
						printf("%02X ",bufferBase[readOffset+j]);
					}
					printf("\n");
				}
				else
				{
					printf("%02X\n",bufferBase[readOffset]);
				}
			}
			r=buffer->EndReadData(true);
			if(r<0)
			{
				printf("EndReadData failed!\n");
			}
		}
	}


	sem_destroy(&sem);
	
	printf("Test pass.\n");
	return 0;
}

